package com.sc.ktapplication.common.net.okdown;

import android.os.Handler;
import android.os.Looper;

import java.io.File;
import java.io.IOException;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Response;

public class OkDownloader {

    private static volatile OkDownloader mInstance;
    private final OkHttpClient mOkHttpClient;

    public OkDownloader(OkHttpClient okHttpClient) {
        if (okHttpClient == null) {
            this.mOkHttpClient = new OkHttpClient();
        } else {
            this.mOkHttpClient = okHttpClient;
        }
    }

    public static OkDownloader initClient(OkHttpClient okHttpClient) {
        if (mInstance == null) {
            synchronized (OkDownloader.class) {
                if (mInstance == null) {
                    mInstance = new OkDownloader(okHttpClient);
                }
            }
        }

        return mInstance;
    }

    public static OkDownloader getInstance() {
        return initClient((OkHttpClient) null);
    }

    public OkHttpClient getOkHttpClient() {
        return this.mOkHttpClient;
    }

    public RequestCall url(String url) {
        return new OkHttpRequest(url).build();
    }

    public Executor defaultCallbackExecutor() {
        return new MainThreadExecutor();
    }

    static class MainThreadExecutor implements Executor {
        private final Handler handler = new Handler(Looper.getMainLooper());

        MainThreadExecutor() {
        }

        public void execute(Runnable r) {
            this.handler.post(r);
        }
    }

    public void execute(RequestCall requestCall, FileCallBack finalCallback) {
        final int id = requestCall.getOkHttpRequest().getId();
        requestCall.getCall().enqueue(new Callback() {
            public void onFailure(Call call, IOException e) {
                sendFailResultCallback(call, e, finalCallback, id);
            }

            public void onResponse(Call call, Response response) {
                try {
                    if (call.isCanceled()) {
                        sendFailResultCallback(call, new IOException("Canceled!"), finalCallback, id);
                        return;
                    }

                    if (!finalCallback.validateReponse(response, id)) {
                        sendFailResultCallback(call, new IOException("request failed , reponse's code is : " + response.code()), finalCallback, id);
                        return;
                    }

                    File o = finalCallback.parseNetworkResponse(response, id);
                    sendSuccessResultCallback(o, finalCallback, id);
                } catch (Exception e) {
                    sendFailResultCallback(call, e, finalCallback, id);
                } finally {
                    if (response.body() != null) {
                        response.body().close();
                    }
                }

            }
        });
    }


    public void sendFailResultCallback(final Call call, final Exception e, final FileCallBack callback, final int id) {
        if (callback != null) {
            defaultCallbackExecutor().execute(new Runnable() {
                public void run() {
                    callback.onError(call, e, id);
                }
            });
        }
    }

    public void sendSuccessResultCallback(final File file, final FileCallBack callback, final int id) {
        if (callback != null) {
            defaultCallbackExecutor().execute(new Runnable() {
                public void run() {
                    callback.onResponse(file, id);
                }
            });
        }
    }

}
